﻿using System;
using JigLibX.Physics;
using Microsoft.Xna.Framework;
using Utilities;

namespace EntitiesAndGameState
{
    /// Descriviamo la geometria di un oggetto (volume, posizione, rotazione, etc.)
    /// tramite il suo descrittore all'interno della fisica
    using Geometry = Body;
    using NukeData = ProjectileData;
    using SecondaryWeapon = Projectile;

    /// <summary>
    /// Una entitá puó appartenere all'AI nemica o al giocatore
    /// </summary>
    public enum Faction
    {
        Enemy,
        Player,
        None
    }


    public enum BonusType
    {
        DestroyAsteroids,
        DestroyAll,
        UpTime,
        TimeWarp
    }


    public enum GarbageType
    {
        EnemyBlueTin,
        EnemyBlueBottle,
        EnemyGreenSandwich,
        EnemyGreenMeat,
        EnemyYellowPaper,
        EnemyYellowBook,
    }

    public enum WeaponType
    {
        Machine_Gun,
        Plasma,
        Double_Plasma,
        Triple_Plasma,
        Laser,
        Nuke,
        Chain_Reaction,
        Smart_Missiles,
        Missiles_Swarm,
        Lightning,
        Shockwave
    }

    public struct WeaponConfig
    {
        public float Speed;
        public float Damage;
        public WeaponType Type;
        public int ShootsNumber;
        public float FireRate;
        public int NumConcurrentShots;
        public float Mass;
        public float Life;
        public float Range;
        public float EnergyConsumption;
        public float ShootProbability;
        public Color InitialColor;
        public Color FinalColor;
        public float ErrorRate;
        public int MinLevelRequired;

        public static WeaponConfig GetWeapon(GarbageType ship_type, WeaponType type)
        {
            var i = (int)ship_type;

            var base_prim_dam = 0.05f;
            var base_sec_dam = 0.3f;
            if (i >= (int)GarbageType.EnemyBlueTin)
                i -= (int)GarbageType.EnemyBlueTin;

            var d = (int)type < 5 ? (i + (int)type) * base_prim_dam : (i + (int)type) * base_sec_dam;

            switch (type)
            {
                // Type, Energy_Cons, ShootProb, Speed, Damage, FireRate, Mass, Life, Range, ShootsNumber, NumConcurrentsShoots, InitialColor, FinalColor, MinLevelRequired
                case WeaponType.Machine_Gun:
                    return GetWeapon(type, 0 * 0.05f, 0.4f, 20.0f, base_prim_dam + d, 0.2f, 0.5f, 0.0f, 0.0f, 4, 1,
                        Color.White, Color.White, 0);
                case WeaponType.Plasma:
                    return GetWeapon(type, 0 * 0.05f, 0.3f, 10.0f, base_prim_dam + d, 0.2f, 0.5f, 0.0f, 0.0f, 4, 1,
                        Color.White, Color.White, 1);
                case WeaponType.Double_Plasma:
                    return GetWeapon(type, 0 * 0.05f, 0.2f, 9.0f, base_prim_dam + d, 0.2f, 0.5f, 0.0f, 0.0f, 4, 1,
                        Color.White, Color.White, 2);
                case WeaponType.Triple_Plasma:
                    return GetWeapon(type, 0 * 0.05f, 0.1f, 8.0f, base_prim_dam + d, 0.8f, 0.5f, 0.0f, 0.0f, 4, 1,
                        Color.White, Color.White, 3);
                case WeaponType.Laser:
                    return GetWeapon(type, 0 * 0.05f, 0.075f, 25.0f, base_prim_dam + d, 0.25f, 0.5f, 0.0f, 20.0f, 12, 1,
                        Color.White, Color.White, 4);
                case WeaponType.Nuke:
                    return GetWeapon(type, 0.53f, 0.3f, 7.0f, base_sec_dam + d, 0.2f, 1.0f, 10.0f, 0.0f, 4, 1,
                        Color.White, Color.White, 2);
                case WeaponType.Missiles_Swarm:
                    return GetWeapon(type, 0.53f, 0.25f, 7.0f, (base_sec_dam + d) / 5.0f, 0.2f, 1.0f, 5.0f, 0.0f, 4, 5,
                        Color.White, Color.White, 4);
                case WeaponType.Smart_Missiles:
                    return GetWeapon(type, 0.53f, 0.2f, 7.0f, (base_sec_dam + d) / 5.0f, 0.2f, 1.0f, 5.0f, 0.0f, 1, 5,
                        Color.White, Color.White, 2);
                case WeaponType.Lightning:
                    return GetWeapon(type, 0.53f, 0.15f, 25.0f, (base_sec_dam + d) / 5.0f, 0.0f, 0.0001f, 100.0f, 60.0f, 0, 5,
                        Color.White, Color.White, 5);
                case WeaponType.Shockwave:
                    return GetWeapon(type, 0.9f, 0.075f, 8.0f, base_sec_dam / 10.0f + d, 10.0f, 10.0f, 10.0f, 15.0f, 1, 1,
                        Color.Red, Color.Yellow, 5);
                case WeaponType.Chain_Reaction:
                    return GetWeapon(type, 0.53f, 0.05f, 7.0f, base_sec_dam + d, 0.0f, 20f, 100.0f, 25.0f, 0, 1,
                        Color.White, Color.White, 1);
                default:
                    return GetWeapon(type, 0.53f, 0.05f, 7.0f, base_sec_dam + d, 0.0f, 20f, 100.0f, 25.0f, 0, 1,
                        Color.White, Color.White, 1);
            }
        }

        public static WeaponConfig GetWeapon(WeaponType type, float energy_consumption, float shoot_prob,
          float speed, float damage, float fire_rate, float mass, float life, float range, int shoots_number,
          int num_concurrent_shots, Color initialColor, Color finalColor, int min_level_required)
        {
            return new WeaponConfig
            {
                Type = type,
                Speed = speed,
                Damage = damage,
                ShootsNumber = shoots_number,
                FireRate = fire_rate,
                NumConcurrentShots = num_concurrent_shots,
                ShootProbability = shoot_prob,
                Mass = mass,
                Life = life,
                Range = range,
                InitialColor = initialColor,
                FinalColor = finalColor,
                EnergyConsumption = energy_consumption,
                ErrorRate = 0.1f,
                MinLevelRequired = min_level_required
            };
        }
    }

    public struct BonusData : IActivable
    {
        public bool IsActive { get; set; }

        public Geometry geometry;
        public float timer;
        public float disappearing_amount;
        public BonusType type;
        public float life;
    }

    public struct Bonus
    {
        public Bonus(bool b)
        {
            self = StructAllocator<BonusData>.New();
        }
        public Reference self;


        public float life
        {
            get
            {
                return StructAllocator<BonusData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].life;
            }
            set
            {
                StructAllocator<BonusData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].life = value;
            }
        }


        public BonusType type
        {
            get
            {
                return StructAllocator<BonusData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].type;
            }
            set
            {
                StructAllocator<BonusData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].type = value;
            }
        }

        public float disappearing_amount
        {
            get
            {
                return StructAllocator<BonusData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].disappearing_amount;
            }
            set
            {
                StructAllocator<BonusData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].disappearing_amount = value;
            }
        }


        public Geometry geometry
        {
            get
            {
                return StructAllocator<BonusData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].geometry;
            }
            set
            {
                StructAllocator<BonusData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].geometry = value;
            }
        }

        public float timer
        {
            get
            {
                return StructAllocator<BonusData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].timer;
            }
            set
            {
                StructAllocator<BonusData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].timer = value;
            }
        }

        public bool HitByEnemy
        {
            get
            {
                var self = this;

                Func<Body, bool> is_enemy = b =>
                {
                    if (b.ExternalData is Projectile)
                        return (((Projectile)b.ExternalData).faction != Faction.Player);
                    else if (b.ExternalData is SecondaryWeapon)
                        return (((SecondaryWeapon)b.ExternalData).faction != Faction.Player);
                    else if (b.ExternalData is Ship)
                        return (((Ship)b.ExternalData).faction != Faction.Player);
                    else return false;
                };

                var cs = this.geometry.CollisionSkin.Collisions;
                //return (from c in cs
                //        let collider = c.SkinInfo.Skin0.Owner == self.geometry ? c.SkinInfo.Skin1 : c.SkinInfo.Skin0
                //        where is_enemy(collider.Owner)
                //        select true).Any();
                for (int i = 0; i < cs.Count; i++)
                {
                    var c = cs[i];
                    var collider = c.SkinInfo.Skin0.Owner == self.geometry ? c.SkinInfo.Skin1 : c.SkinInfo.Skin0;
                    if (is_enemy(collider.Owner)) return true;
                }
                return false;
            }
        }

        public bool HitByPlayer
        {
            get
            {
                var cs = this.geometry.CollisionSkin.Collisions;
                //for_each (var c in cs)
                for (int i = 0; i < cs.Count; i++)
                {
                    var c = cs[i];
                    var collider = c.SkinInfo.Skin0.Owner == this.geometry ? c.SkinInfo.Skin1.Owner : c.SkinInfo.Skin0.Owner;
                    if ((collider.ExternalData is Projectile && ((Projectile)collider.ExternalData).faction == Faction.Player) ||
                        (collider.ExternalData is Ship && ((Ship)collider.ExternalData).faction == Faction.Player))
                        return true;
                }
                return false;
            }
        }
    }


    /// <summary>
    /// Un proiettile puó inseguire:
    /// * niente
    /// * un missile
    /// * una nave
    /// </summary>
    public enum TargetType
    {
        None,
        Ship,
        Bonus,
        Asteroid
    }

    /// <summary>
    /// Un Laser ha geometria, fazione, timer e dimensione come un missile nucleare <seealso cref="NukeData"/>
    /// ma contiene anche una reference ad un missile o ad una nave che sta inseguendo: in questo modo i nostri
    /// proiettili fanno il "tracking" del loro obiettivo.
    /// </summary>
    public struct ProjectileData : IActivable
    {
        public bool IsActive { get; set; }

        public Geometry geometry;
        public Faction faction;
        public float age;
        public float size;
        public float life;
        public TargetType target_type;
        public SecondaryWeapon target_nuke;
        public Ship target_ship;
        public Bonus target_bonus;
        public WeaponConfig weapon_config;

        public Ship shooter;
        public Body shooted_body;

        public Geometry target_geometry
        {
            get
            {
                switch (target_type)
                {
                    case TargetType.Ship: return target_ship.geometry;
                    case TargetType.Bonus: return target_bonus.geometry;
                }
                return null;
            }
        }

        /// <summary>
        /// Calcoliamo con DamagingColliders le entitá nemiche di questa che vi sono in collisione. Per
        /// calcolarle andiamo a vedere tutte le geometrie in collisione, vediamo che entitá é associata
        /// al tag (ExternalData) della geometria collidente e consultiamo il campo faction dell'entitá:
        /// se la fazione del collisore é diversa dalla nostra, allora é un nemico con cui stiamo
        /// collidendo.
        /// </summary>
        //public IEnumerable<Body> DamagingColliders
        //{
        //    get
        //    {
        //        var self = this;

        //        Func<Body, bool> is_enemy = b =>
        //        {
        //            if (b.ExternalData is Projectile)
        //                return true; //(((Laser)b.ExternalData).faction != self.faction);
        //            else if (b.ExternalData is SecondaryWeapon)
        //                return true; //(((Nuke)b.ExternalData).faction != self.faction);
        //            else if (b.ExternalData is Ship)
        //                return true; //(((Ship)b.ExternalData).faction != self.faction);
        //            else if (b.ExternalData is Bonus)
        //                return true; //(((Ship)b.ExternalData).faction != self.faction);
        //            else if (b.ExternalData is Asteroid)
        //                return true;
        //            else return false;
        //        };

        //        var cs = this.geometry.CollisionSkin.Collisions;
        //        if (cs.Count == 0)
        //            return null;
        //        return from c in cs
        //               let collider = c.SkinInfo.Skin0.Owner == self.geometry ? c.SkinInfo.Skin1 : c.SkinInfo.Skin0
        //               where is_enemy(collider.Owner)
        //               select collider.Owner;
        //    }
        //}

        public Res foldEnemies<Res>(Func<Body, Res, Res> fold, Res acc)
        {
            var cs = this.geometry.CollisionSkin.Collisions;
            //for_each (var c in cs)
            for (int i = 0; i < cs.Count; i++)
            {
                var c = cs[i];
                var collider = c.SkinInfo.Skin0.Owner == this.geometry ? c.SkinInfo.Skin1.Owner : c.SkinInfo.Skin0.Owner;
                if (collider.ExternalData is Projectile ||
                    collider.ExternalData is SecondaryWeapon ||
                    collider.ExternalData is Ship ||
                    collider.ExternalData is Asteroid ||
                    collider.ExternalData is Bonus)
                    acc = fold(collider, acc);
            }
            return acc;
        }

    }

    /// <summary>
    /// Reference ad un ProjectileData
    /// </summary>
    public struct Projectile
    {
        public ProjectileData OwnValue { get { return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex]; } }

        public Projectile(bool b)
        {
            self = StructAllocator<ProjectileData>.New();
        }
        public Reference self;

        public Geometry geometry
        {
            get
            {
                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].geometry;
            }
            set
            {
                StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].geometry = value;
            }
        }


        public float life
        {
            get
            {
                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].life;
            }
            set
            {
                StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].life = value;
            }
        }


        public Faction faction
        {
            get
            {
                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].faction;
            }
            set
            {
                StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].faction = value;
            }
        }

        public float age
        {
            get
            {
                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].age;
            }
            set
            {
                StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].age = value;
            }
        }

        public float size
        {
            get
            {
                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].size;
            }
            set
            {
                StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].size = value;
            }
        }

        //public IEnumerable<Body> DamagingColliders
        //{
        //    get
        //    {
        //        return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].DamagingColliders;
        //    }
        //}

        public Res foldEnemies<Res>(Func<Body, Res, Res> fold, Res acc)
        {
            return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].foldEnemies(fold, acc);
        }

        public TargetType target_type
        {
            get
            {
                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].target_type;
            }
            set
            {
                StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].target_type = value;
            }
        }

        public SecondaryWeapon target_nuke
        {
            get
            {
                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].target_nuke;
            }
            set
            {
                StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].target_nuke = value;
            }
        }

        public Ship target_ship
        {
            get
            {
                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].target_ship;
            }
            set
            {
                StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].target_ship = value;
            }
        }

        public Bonus target_bonus
        {
            get
            {
                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].target_bonus;
            }
            set
            {
                StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].target_bonus = value;
            }
        }

        public WeaponConfig weapon_config
        {
            get
            {
                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].weapon_config;
            }
            set
            {
                StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].weapon_config = value;
            }
        }

        public Ship shooter
        {
            get
            {
                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].shooter;
            }
            set
            {
                StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].shooter = value;
            }
        }

        public Body shot_body
        {
            get
            {
                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].shooted_body;
            }
            set
            {
                StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].shooted_body = value;
            }
        }


        public Geometry target_geometry
        {
            get
            {
                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].target_geometry;
            }
        }

    }


    /// <summary>
    /// Una nave ha associata una vita residua.
    /// </summary>
    public struct Stats
    {
        public int NumberOfSquash;
        public float MaxLife;
        public float CurrentLife;
    }


    /// <summary>
    /// Un motore ha una posizione relativa entro il modello della nave associata e
    /// una potenza erogata corrente in percentuale.
    /// </summary>
    public struct EngineData : IActivable
    {
        public bool IsActive { get; set; }
        public Vector3 Location;
        public float Throttle;
    }


    /// <summary>
    /// Reference ad un EngineData.
    /// </summary>
    public struct Engine
    {
        public Engine(bool b)
        {
            self = StructAllocator<EngineData>.New();
        }
        public Reference self;

        public Vector3 Location
        {
            get
            {
                return StructAllocator<EngineData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].Location;
            }
            set
            {
                StructAllocator<EngineData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].Location = value;
            }
        }


        public float Throttle
        {
            get
            {
                return StructAllocator<EngineData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].Throttle;
            }
            set
            {
                StructAllocator<EngineData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].Throttle = value;
            }
        }
    }

    /// <summary>
    /// Una nave puó essere
    /// * all'entrata del warp
    /// * all'uscita del warp
    /// * al di fuori del warp
    /// </summary>
    public enum WarpType
    {
        Entering,
        Exiting,
        None
    }

    /// <summary>
    /// Definiamo una struttura per contenere un waypoint (o nulla se il
    /// booleano é a false); performa meglio avere struct che classi, ma
    /// se usiamo struct dobbiamo poter rappresentare un oggetto null
    /// </summary>
    public struct MaybeWaypoint
    {
        public Vector3 Position;
        public bool HasValue;
    }

    /// <summary>
    /// La nave del giocatore contiene:
    /// * geometria
    /// * vita corrente
    /// * una lista di motori
    /// * numero di vite residue
    /// * informazioni sul warp
    /// * prossimo waypoint
    /// * timer per determinare se la nave puó sparare (per evitare che una nave spari troppo spesso)
    /// * un numero di missili disponibili
    /// </summary>
    public struct PlayerShip
    {
        public static readonly float WARP_TRANSITION_TIME = 0.25f;
        public static readonly float X_TRANSITION_TIME = 0.5f;

        public int num_lives;
        public float warp_state;
        public float warping_in_timer;
        public float warping_out_timer;
        public WarpType warp_type;
        public MaybeWaypoint waypoint;
        public float shield;
        public float age;
        public float INVULNERABILITY_SPAWN_TIME;
        public float[] shields_spawn_time;

        public PlayerShip(bool b)
        {
            num_lives = 0;
            warp_state = 1.0f;
            warping_in_timer = 0.0f;
            warping_out_timer = 0.0f;
            warp_type = WarpType.None;
            waypoint = new MaybeWaypoint();
            self = StructAllocator<ShipData>.New();
            shield = 0;
            age = 0.0f;
            INVULNERABILITY_SPAWN_TIME = 3.0f;
            shields_spawn_time = new float[] { 0, 0, 0, 0 };
        }
        public Reference self;

        public ShipData OwnValue { get { return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex]; } }

        public int primary_active
        {
            get
            {
                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].primary_active;
            }
            set
            {
                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].primary_active = value;
            }
        }

        public int secondary_active
        {
            get
            {
                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].secondary_active;
            }
            set
            {
                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].secondary_active = value;
            }
        }

        public float energy
        {
            get
            {
                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].energy;
            }
            set
            {
                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].energy = value;
            }
        }

        public float time_since_last_laser_shot
        {
            get
            {
                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].time_since_last_laser_shot;
            }
            set
            {
                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].time_since_last_laser_shot = value;
            }
        }

        public float time_since_last_nuke_shot
        {
            get
            {
                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].time_since_last_nuke_shot;
            }
            set
            {
                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].time_since_last_nuke_shot = value;
            }
        }

        public Geometry geometry
        {
            get
            {
                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].geometry;
            }
            set
            {
                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].geometry = value;
            }
        }


        public Stats stats
        {
            get
            {
                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].stats;
            }
            set
            {
                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].stats = value;
            }
        }


        public Engine[] engines
        {
            get
            {
                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].engines;
            }
            set
            {
                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].engines = value;
            }
        }

        public Faction faction
        {
            get
            {
                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].faction;
            }
            set
            {
                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].faction = value;
            }
        }

        //public IEnumerable<Body> DamagingColliders
        //{
        //    get
        //    {
        //        return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].DamagingColliders;
        //    }
        //}

        public Res foldEnemies<Res>(Func<Body, Res, Res> fold, Res acc)
        {
            return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].foldEnemies(fold, acc);
        }

        public void Update(float dt, float max_speed)
        {
            geometry.Force = -geometry.Velocity * geometry.Mass * 2.0f;
            geometry.Torque = Vector3.Transform(-geometry.AngularVelocity, geometry.BodyInertia) * 2.0f;
            geometry.UpdateVelocity(dt);

            var throttle = MathHelper.SmoothStep(0.0f, 1.0f, this.geometry.Velocity.Length() / max_speed);
            for (int j = 0; j < this.engines.Length; j++)
                this.engines[j].Throttle = throttle;
        }

        public Ship AsShip
        {
            get { return new Ship() { self = this.self }; }
            set { self = value.self; }
        }
    }


    public struct ShipDescription
    {
        public Color circleColor;
        public string ModelPath;
        public float Speed;
        public float TimeToWarp;
        public float EnergyGeneratorLevel;
        public float MaxShield;
        public ArrayList<WeaponConfig> PrimaryWeapons;
        public ArrayList<WeaponConfig> SecondaryWeapons;
        public float PrimaryShotSpawnTime;
        public float SecondaryShotSpawnTime;
        public float Armor;
        public bool ShockWaveOnExplode;
        public ShockWaveData ShockWaveData;
        public GarbageType ShipType;
        public int Level
        {
            get
            {
                var st = (int)ShipType;
                return st - (int)GarbageType.EnemyBlueTin;
            }
        }
        public float DamageMultiplier
        {
            get
            {
                var st = (int)ShipType;
                if (st <= (int)GarbageType.EnemyGreenMeat)
                    return (float)Math.Pow(1.65f, st - (int)GarbageType.EnemyBlueTin);
                else return (float)Math.Pow(2.0f, Level);
            }
        }
        public float InitialLifeMultiplier
        {
            get
            {
                var st = (int)ShipType;
                if (st <= (int)GarbageType.EnemyGreenMeat)
                    return (float)Math.Pow(2.0f, st - (int)GarbageType.EnemyBlueTin);
                else
                    return (float)Math.Pow(2.0f, Level);
            }
        }
        public int MaxConcurrentTargets;
    }

    public enum Container
    {
        Yellow,
        Green, 
        Blue
    }
    /// <summary>
    /// La nave contiene:
    /// * geometria
    /// * vita corrente
    /// * una lista di motori
    /// * una fazione
    /// * timer per determinare se la nave puó sparare (per evitare che una nave spari troppo spesso)
    /// * un numero di missili disponibili
    /// </summary>
    public struct ShipData : IActivable
    {
        public bool IsActive { get; set; }
        public Geometry geometry;
        public Stats stats;
        public Engine[] engines;
        public Faction faction;
        public Vector3 direction;
        public float time_since_last_laser_shot;
        public float time_since_last_nuke_shot;
        public float energy;
        public int primary_active;
        public int secondary_active;
        public GarbageType ship_type;
        public Container relative_container;
        public bool is_touch_enable;
        public ShipDescription ship_description;
        public bool is_warp_running;
        public float time_to_finish_warp;
        public bool is_x_running;
        public float time_to_finish_x;

        /// <summary>
        /// Calcoliamo con DamagingColliders le entitá nemiche di questa che vi sono in collisione. Per
        /// calcolarle andiamo a vedere tutte le geometrie in collisione, vediamo che entitá é associata
        /// al tag (ExternalData) della geometria collidente e consultiamo il campo faction dell'entitá:
        /// se la fazione del collisore é diversa dalla nostra, allora é un nemico con cui stiamo
        /// collidendo.
        /// </summary>
        //public IEnumerable<Body> DamagingColliders
        //{
        //    get
        //    {
        //        var self = this;

        //        Func<Body, bool> is_enemy = b =>
        //        {
        //            if (b.ExternalData is Projectile)
        //                return true; //(((Laser)b.ExternalData).faction != self.faction);
        //            else if (b.ExternalData is SecondaryWeapon)
        //                return true; //(((Nuke)b.ExternalData).faction != self.faction);
        //            else if (b.ExternalData is Ship)
        //                return true; //(((Ship)b.ExternalData).faction != self.faction);
        //            else if (b.ExternalData is Asteroid)
        //                return true;
        //            else return false;
        //        };

        //        var cs = this.geometry.CollisionSkin.Collisions;
        //        if (cs.Count == 0)
        //            return null;
        //        return from c in cs
        //               let collider = c.SkinInfo.Skin0.Owner == self.geometry ? c.SkinInfo.Skin1 : c.SkinInfo.Skin0
        //               where is_enemy(collider.Owner)
        //               select collider.Owner;
        //    }
        //}


        public Res foldEnemies<Res>(Func<Body, Res, Res> fold, Res acc)
        {
            var cs = this.geometry.CollisionSkin.Collisions;
            //for_each (var c in cs)
            //{
            for (int i = 0; i < cs.Count; i++)
            {
                var c = cs[i];
                var collider = c.SkinInfo.Skin0.Owner == this.geometry ? c.SkinInfo.Skin1.Owner : c.SkinInfo.Skin0.Owner;
                if (collider.ExternalData is Projectile ||
                    collider.ExternalData is SecondaryWeapon ||
                    collider.ExternalData is Ship ||
                    collider.ExternalData is Asteroid)
                    acc = fold(collider, acc);
            }
            return acc;
        }
    }

    /// <summary>
    /// Reference a ShipData.
    /// </summary>
    public struct Ship
    {
        public Ship(bool b)
        {
            self = StructAllocator<ShipData>.New();
        }

        public void set_touch(bool value)
        {
          this.is_touch_enable = value;
        }

        public Reference self;

        public ShipData OwnValue { get { return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex]; } }

        public bool is_touch_enable
        {
          get
          {
            return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].is_touch_enable;
          }
          set
          {
            StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].is_touch_enable = value;
          }
        }

        public Container relative_container
        {
            get
            {
                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].relative_container;
            }
            set
            {
                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].relative_container = value;
            }
        }
        public bool is_warp_running
        {
            get
            {
                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].is_warp_running;
            }
            set
            {
                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].is_warp_running = value;
            }
        }
        public float time_to_finish_warp
        {
            get
            {
                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].time_to_finish_warp;
            }
            set
            {
                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].time_to_finish_warp = value;
            }
        }
        public bool is_x_running
        {
            get
            {
                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].is_x_running;
            }
            set
            {
                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].is_x_running = value;
            }
        }
        public float time_to_finish_x
        {
            get
            {
                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].time_to_finish_x;
            }
            set
            {
                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].time_to_finish_x = value;
            }
        }
        public int primary_active
        {
            get
            {
                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].primary_active;
            }
            set
            {
                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].primary_active = value;
            }
        }

        public int secondary_active
        {
            get
            {
                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].secondary_active;
            }
            set
            {
                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].secondary_active = value;
            }
        }
        public Vector3 direction
        {
            get
            {
                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].direction;
            }
            set
            {
                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].direction = value;
            }
        }
        public float energy
        {
            get
            {
                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].energy;
            }
            set
            {
                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].energy = value;
            }
        }

        public float time_since_last_primary_shot
        {
            get
            {
                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].time_since_last_laser_shot;
            }
            set
            {
                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].time_since_last_laser_shot = value;
            }
        }

        public float time_since_last_secondary_shot
        {
            get
            {
                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].time_since_last_nuke_shot;
            }
            set
            {
                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].time_since_last_nuke_shot = value;
            }
        }

        public Geometry geometry
        {
            get
            {
                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].geometry;
            }
            set
            {
                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].geometry = value;
            }
        }


        public Stats stats
        {
            get
            {
                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].stats;
            }
            set
            {
                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].stats = value;
            }
        }


        public Engine[] engines
        {
            get
            {
                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].engines;
            }
            set
            {
                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].engines = value;
            }
        }

        public Faction faction
        {
            get
            {
                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].faction;
            }
            set
            {
                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].faction = value;
            }
        }

        //public IEnumerable<Body> DamagingColliders
        //{
        //    get
        //    {
        //        return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].DamagingColliders;
        //    }
        //}

        public Res foldEnemies<Res>(Func<Body, Res, Res> fold, Res acc)
        {
            return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].foldEnemies(fold, acc);
        }

        public GarbageType ship_type
        {
            get
            {
                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].ship_type;
            }

            set
            {
                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].ship_type = value;
            }
        }

        public ShipDescription ship_description
        {
            get
            { return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].ship_description; }

            set
            { StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].ship_description = value; }
        }



        public void Update(float dt, float max_speed)
        {
            geometry.Force = -geometry.Velocity * geometry.Mass * 2.0f;
            geometry.Torque = Vector3.Transform(-geometry.AngularVelocity, geometry.BodyInertia) * 2.0f;
            geometry.UpdateVelocity(dt);

            //var throttle = MathHelper.SmoothStep(0.0f, 1.0f, this.geometry.Velocity.Length() * max_speed);
            //for (int j = 0; j < this.engines.Length; j++)
            //    this.engines[j].Throttle = throttle;
        }

        public void AdjustLifeByLevel()
        {
            var stats = this.stats;
            stats.CurrentLife *= this.ship_description.InitialLifeMultiplier;
            stats.MaxLife *= this.ship_description.InitialLifeMultiplier;
            this.stats = stats;
        }
    }


    /// <summary>
    /// Una esplosione puó derivare da
    /// * oggetti non specificati
    /// * un missile
    /// * una nave
    /// * un proiettile
    /// </summary>
    public enum ExplosionType
    {
        None,
        Nuke,
        Ship,
        Laser,
        Asteroid
    }

    /// <summary>
    /// Una esplosione ha un oggetto che le fa da origine (scelto in base alla 
    /// flag explosion_type) e una posizione in cui va messa indipendentemente
    /// dall'oggetto esploso.
    /// </summary>
    public struct ExplosionData : IActivable
    {
        public bool IsActive { get; set; }
        public ExplosionType explosion_type;
        public ProjectileData originating_laser;
        public NukeData originating_nuke;
        public ShipData originating_ship;
        public AsteroidData originating_asteroid;
        public Vector3 position;
    }

    /// <summary>
    /// Reference a ExplosionData.
    /// </summary>
    public struct Explosion
    {
        public Explosion(bool b)
        {
            self = StructAllocator<ExplosionData>.New();
        }
        public Reference self;

        public ExplosionType explosion_type
        {
            get
            {
                return StructAllocator<ExplosionData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].explosion_type;
            }
            set
            {
                StructAllocator<ExplosionData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].explosion_type = value;
            }
        }

        public ShipData originating_ship
        {
            get
            {
                return StructAllocator<ExplosionData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].originating_ship;
            }
            set
            {
                StructAllocator<ExplosionData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].originating_ship = value;
            }
        }

        public ProjectileData originating_laser
        {
            get
            {
                return StructAllocator<ExplosionData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].originating_laser;
            }
            set
            {
                StructAllocator<ExplosionData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].originating_laser = value;
            }
        }

        public NukeData originating_nuke
        {
            get
            {
                return StructAllocator<ExplosionData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].originating_nuke;
            }
            set
            {
                StructAllocator<ExplosionData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].originating_nuke = value;
            }
        }


        public AsteroidData originating_asteroid
        {
            get
            {
                return StructAllocator<ExplosionData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].originating_asteroid;
            }
            set
            {
                StructAllocator<ExplosionData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].originating_asteroid = value;
            }
        }

        public Vector3 position
        {
            get
            {
                return StructAllocator<ExplosionData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].position;
            }
            set
            {
                StructAllocator<ExplosionData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].position = value;
            }
        }
    }

    public struct ShockWaveData : IActivable
    {
        public bool IsActive
        {
            get
            {
                return radius <= range && range != 0;
            }
            set
            {
            }
        }
        public Vector3 position;
        public Color finalColor;
        public Color initialColor;
        public float speed;
        public float range;
        public Faction faction;
        public float damage;
        public float radius;
        public Ship shooter;
    }

    public struct ShockWave
    {
        public ShockWave(bool b)
        {
            self = StructAllocator<ShockWaveData>.New();
        }
        public Reference self;

        public ShockWaveData OwnValue { get { return StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex]; } }

        public Faction faction
        {
            get
            {
                return StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].faction;
            }
            set
            {
                StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].faction = value;
            }
        }
        public Vector3 position
        {
            get
            {
                return StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].position;
            }
            set
            {
                StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].position = value;
            }
        }
        public Color initialColor
        {
            get
            {
                return StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].initialColor;
            }
            set
            {
                StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].initialColor = value;
            }
        }
        public Color finalColor
        {
            get
            {
                return StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].finalColor;
            }
            set
            {
                StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].finalColor = value;
            }
        }
        public float speed
        {
            get
            {
                return StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].speed;
            }
            set
            {
                StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].speed = value;
            }
        }
        public float damage
        {
            get
            {
                return StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].damage;
            }
            set
            {
                StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].damage = value;
            }
        }
        public float radius
        {
            get
            {
                return StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].radius;
            }
            set
            {
                StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].radius = value;
            }
        }
        public float range
        {
            get
            {
                return StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].range;
            }
            set
            {
                StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].range = value;
            }
        }

        public Ship shooter
        {
            get
            {
                return StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].shooter;
            }
            set
            {
                StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].shooter = value;
            }
        }
    }

    /// <summary>
    /// Un missile nucleare contiene una geometria, una fazione, un timer (per eliminare i vecchi missili che
    /// non hanno raggiunto l'obiettivo) e una dimensione.
    /// </summary>
    public struct AsteroidData : IActivable
    {
        public bool IsActive { get; set; }

        public Geometry geometry;
        public float size;
        public Stats stat;
        


        public Res foldEnemies<Res>(Func<Body, Res, Res> fold, Res acc)
        {
            var cs = this.geometry.CollisionSkin.Collisions;
            //for_each (var c in cs)
            //{
            for (int i = 0; i < cs.Count; i++)
            {
                var c = cs[i];
                var collider = c.SkinInfo.Skin0.Owner == this.geometry ? c.SkinInfo.Skin1.Owner : c.SkinInfo.Skin0.Owner;
                if (collider.ExternalData is Projectile ||
                    collider.ExternalData is SecondaryWeapon ||
                    collider.ExternalData is Ship)
                    acc = fold(collider, acc);
            }
            return acc;
        }
    }


    /// <summary>
    /// Asteroid é il tipo di una reference (che fa anche da proxy) ad un AsteroidData
    /// </summary>
    public struct Asteroid
    {
        public AsteroidData OwnValue { get { return StructAllocator<AsteroidData>.Chunks[self.ChunkIndex].Items[self.ItemIndex]; } }

        public Asteroid(bool b)
        {
            self = StructAllocator<AsteroidData>.New();
        }

        public Reference self;

        public Geometry geometry
        {
            get
            {
                return StructAllocator<AsteroidData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].geometry;
            }
            set
            {
                StructAllocator<AsteroidData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].geometry = value;
            }
        }

        public float size
        {
            get
            {
                return StructAllocator<AsteroidData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].size;
            }
            set
            {
                StructAllocator<AsteroidData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].size = value;
            }
        }

        public Stats stat
        {
            get
            {
                return StructAllocator<AsteroidData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].stat;
            }
            set
            {
                StructAllocator<AsteroidData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].stat = value;
            }
        }

        //public IEnumerable<Body> DamagingColliders
        //{
        //    get
        //    {
        //        return StructAllocator<AsteroidData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].DamagingColliders;
        //    }
        //}


        //public void Damaging_Colliders(List<Body> acc)
        //{
        //        StructAllocator<AsteroidData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].Damaging_Colliders(acc);
        //}

        public Res foldEnemies<Res>(Func<Body, Res, Res> fold, Res acc)
        {
            return StructAllocator<AsteroidData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].foldEnemies(fold, acc);
        }
    }



}


//using System;
//using System.Collections.Generic;
//using System.Linq;
//using Microsoft.Xna.Framework;
//using Microsoft.Xna.Framework.Audio;
//using Microsoft.Xna.Framework.Content;
//using Microsoft.Xna.Framework.GamerServices;
//using Microsoft.Xna.Framework.Graphics;
//using Microsoft.Xna.Framework.Input;
//using Microsoft.Xna.Framework.Media;
//using System.Threading;
//using JigLibX.Physics;
//using JigLibX.Collision;
//using JigLibX.Geometry;
//using Microsoft.Xna.Framework.Input.Touch;
//using Services;
//using Utilities;

//namespace XNAGame
//{
//    /// Descriviamo la geometria di un oggetto (volume, posizione, rotazione, etc.)
//    /// tramite il suo descrittore all'interno della fisica
//    using Geometry = Body;

//    using SecondaryWeapon = Projectile;
//    using NukeData = ProjectileData;

//    /// <summary>
//    /// Una entitá puó appartenere all'AI nemica o al giocatore
//    /// </summary>
//    public enum Faction
//    {
//        Enemy,
//        Player,
//        None
//    }


//    public enum BonusType
//    {
//        WarpCharge,
//        Nuke,
//        ShieldCharge,
//        TimeWarp
//    }


//    public enum GarbageType
//    {
//        PlayerBaseShip,
//        PlayerFighter,
//        PlayerDestroyer,
//        PlayerCorvette,
//        PlayerFrigate,
//        PlayerCruiser,
//        EnemyYellowBook,
//        EnemyGreenSandwich,
//        EnemyYellowPaper,
//        EnemyBlueBottle,
//        EnemyFighther,
//        Boss1,
//        Boss2,
//        Boss3,
//        Boss4,
//        Boss5
//    }

//    public enum WeaponType
//    {
//        Plasma,
//        Laser,
//        Double_Plasma,
//        Machine_Gun,
//        Triple_Plasma,
//        Nuke,
//        //NonTrackingNuke,
//        Missiles_Swarm,
//        Lightning,
//        Chain_Reaction,
//        Smart_Missiles,
//        Shockwave
//    }

//    public struct WeaponConfig
//    {
//        public float Speed;
//        public float Damage;
//        public WeaponType Type;
//        //public float WeaponAverage { get { return (Damage + Speed / 10) * 0.5f; } }
//        public int ShootsNumber;
//        public float FireRate;
//        public int NumConcurrentShots;
//        public float Mass;
//        public float Life;
//        public float Range;
//        public float EnergyConsumption;
//        public Color InitialColor;
//        public Color FinalColor;

//        public static WeaponConfig GetWeapon(WeaponType type)
//        {
//            switch (type)
//            {
//                // Type, Speed, Damage, FireRate, Mass, Life, Range, ShootsNumber, NumConcurrentsShoots
//                case WeaponType.Machine_Gun:
//                    return GetWeapon(type, 0.05f, 20.0f, 0.5f, 0.2f, 0.5f, 0.0f, 0.0f, 4, 1, Color.White, Color.White);  
//                case WeaponType.Plasma:
//                    return GetWeapon(type, 0.05f, 10.0f, 0.1f, 0.2f, 0.5f, 0.0f, 0.0f, 4, 1, Color.White, Color.White);
//                case WeaponType.Double_Plasma:
//                    return GetWeapon(type, 0.05f, 9.0f, 0.3f, 0.2f, 0.5f, 0.0f, 0.0f, 4, 1, Color.White, Color.White);
//                case WeaponType.Triple_Plasma:
//                    return GetWeapon(type, 0.05f, 8.0f, 0.5f, 0.8f, 0.5f, 0.0f, 0.0f, 4, 1, Color.White, Color.White);
//                case WeaponType.Laser:
//                    return GetWeapon(type, 0.05f, 25.0f, 0.05f, 0.25f, 0.5f, 0.0f, 20.0f, 12, 1, Color.White, Color.White);
//                case WeaponType.Lightning:
//                    return GetWeapon(type, 0.33f, 25.0f, 0.1f, 0.0f, 0.0001f, 100.0f, 15.0f, 0, 5, Color.White, Color.White);
//                case WeaponType.Nuke:
//                    return GetWeapon(type, 0.33f, 7.0f, 0.5f, 0.2f, 1.0f, 10.0f, 0.0f, 4, 1, Color.White, Color.White);
//                case WeaponType.Missiles_Swarm:
//                    return GetWeapon(type, 0.33f, 7.0f, 0.5f, 0.2f, 1.0f, 5.0f, 0.0f, 4, 5, Color.White, Color.White);
//                case WeaponType.Shockwave:
//                    return GetWeapon(type, 0.33f, 8.0f, 0.05f, 10.0f, 10.0f, 10.0f, 16.0f, 1, 1, Color.Red, Color.Yellow);
//                case WeaponType.Smart_Missiles:
//                    return GetWeapon(type, 0.33f, 7.0f, 0.4f, 0.2f, 1.0f, 5.0f, 0.0f, 1, 5, Color.White, Color.White);
//                case WeaponType.Chain_Reaction:
//                    return GetWeapon(type, 0.33f, 7.0f, 5.1f, 0.0f, 20f, 100.0f, 25.0f, 0, 1, Color.White, Color.White);
//            }

//            return GetWeapon(type, .0f, .0f, .0f, .0f, .0f, .0f, .0f, 0, 0, Color.White, Color.White);
//        }

//        public static WeaponConfig GetWeapon(WeaponType type, float energy_consumption, float speed, float damage, float fire_rate, float mass, float life, float range, int shoots_number, int num_concurrent_shots, Color initialColor, Color finalColor)
//        {
//            return new WeaponConfig { Type = type, Speed = speed, Damage = damage, ShootsNumber = shoots_number, 
//                FireRate = fire_rate,
//                NumConcurrentShots = num_concurrent_shots,
//                Mass = mass,
//                Life = life,
//                Range = range,
//                InitialColor=initialColor,
//                FinalColor=finalColor,
//                EnergyConsumption = energy_consumption
//            };
//        }
//    }

//    public struct BonusData : IActivable
//    {
//        public bool IsActive { get; set; }

//        public Geometry geometry;
//        public float timer;
//        public float disappearing_amount;
//        public BonusType type;
//        public float life;
//    }

//    public struct Bonus
//    {
//        public Bonus(bool b)
//        {
//            self = StructAllocator<BonusData>.New();
//        }
//        public Reference self;


//        public float life
//        {
//            get
//            {
//                return StructAllocator<BonusData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].life;
//            }
//            set
//            {
//                StructAllocator<BonusData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].life = value;
//            }
//        }


//        public BonusType type
//        {
//            get
//            {
//                return StructAllocator<BonusData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].type;
//            }
//            set
//            {
//                StructAllocator<BonusData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].type = value;
//            }
//        }

//        public float disappearing_amount
//        {
//            get
//            {
//                return StructAllocator<BonusData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].disappearing_amount;
//            }
//            set
//            {
//                StructAllocator<BonusData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].disappearing_amount = value;
//            }
//        }


//        public Geometry geometry
//        {
//            get
//            {
//                return StructAllocator<BonusData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].geometry;
//            }
//            set
//            {
//                StructAllocator<BonusData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].geometry = value;
//            }
//        }

//        public float timer
//        {
//            get
//            {
//                return StructAllocator<BonusData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].timer;
//            }
//            set
//            {
//                StructAllocator<BonusData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].timer = value;
//            }
//        }

//        public bool HitByEnemy
//        {
//            get
//            {
//                var self = this;

//                Func<Body, bool> is_enemy = b =>
//                {
//                    if (b.ExternalData is Projectile)
//                        return (((Projectile)b.ExternalData).faction != Faction.Player);
//                    else if (b.ExternalData is SecondaryWeapon)
//                        return (((SecondaryWeapon)b.ExternalData).faction != Faction.Player);
//                    else if (b.ExternalData is Ship)
//                        return (((Ship)b.ExternalData).faction != Faction.Player);
//                    else return false;
//                };

//                var cs = this.geometry.CollisionSkin.Collisions;
//                //return (from c in cs
//                //        let collider = c.SkinInfo.Skin0.Owner == self.geometry ? c.SkinInfo.Skin1 : c.SkinInfo.Skin0
//                //        where is_enemy(collider.Owner)
//                //        select true).Any();
//                for (int i = 0; i < cs.Count; i++)
//                {
//                    var c = cs[i];
//                    var collider = c.SkinInfo.Skin0.Owner == self.geometry ? c.SkinInfo.Skin1 : c.SkinInfo.Skin0;
//                    if(is_enemy(collider.Owner)) return true;
//                }
//                return false;
//            }
//        }

//        public bool HitByPlayer
//        {
//            get
//            {
//                var cs = this.geometry.CollisionSkin.Collisions;
//                //for_each (var c in cs)
//                for (int i = 0; i < cs.Count; i++)
//                {
//                    var c = cs[i];
//                    var collider = c.SkinInfo.Skin0.Owner == this.geometry ? c.SkinInfo.Skin1.Owner : c.SkinInfo.Skin0.Owner;
//                    if ((collider.ExternalData is Projectile && ((Projectile)collider.ExternalData).faction == Faction.Player) ||
//                        (collider.ExternalData is Ship && ((Ship)collider.ExternalData).faction == Faction.Player))
//                        return true;
//                }
//                return false;
//            }
//        }
//    }


//    /// <summary>
//    /// Un proiettile puó inseguire:
//    /// * niente
//    /// * un missile
//    /// * una nave
//    /// </summary>
//    public enum TargetType
//    {
//        None,
//        Nuke,
//        Ship,
//        Bonus
//    }

//    /// <summary>
//    /// Un Laser ha geometria, fazione, timer e dimensione come un missile nucleare <seealso cref="NukeData"/>
//    /// ma contiene anche una reference ad un missile o ad una nave che sta inseguendo: in questo modo i nostri
//    /// proiettili fanno il "tracking" del loro obiettivo.
//    /// </summary>
//    public struct ProjectileData : IActivable
//    {
//        public bool IsActive { get; set; }

//        public Geometry geometry;
//        public Faction faction;
//        public float age;
//        public float size;
//        public float life;
//        public TargetType target_type;
//        public SecondaryWeapon target_nuke;
//        public Ship target_ship;
//        public Bonus target_bonus;
//        public WeaponConfig weapon_config;

//        public Ship shooter;
//        public Body shooted_body;

//        public Geometry target_geometry
//        {
//            get
//            {
//                switch (target_type)
//                {
//                    case TargetType.Nuke: return target_nuke.geometry;
//                    case TargetType.Ship: return target_ship.geometry;
//                    case TargetType.Bonus: return target_bonus.geometry;
//                }
//                return null;
//            }
//        }

//        /// <summary>
//        /// Calcoliamo con DamagingColliders le entitá nemiche di questa che vi sono in collisione. Per
//        /// calcolarle andiamo a vedere tutte le geometrie in collisione, vediamo che entitá é associata
//        /// al tag (ExternalData) della geometria collidente e consultiamo il campo faction dell'entitá:
//        /// se la fazione del collisore é diversa dalla nostra, allora é un nemico con cui stiamo
//        /// collidendo.
//        /// </summary>
//        //public IEnumerable<Body> DamagingColliders
//        //{
//        //    get
//        //    {
//        //        var self = this;

//        //        Func<Body, bool> is_enemy = b =>
//        //        {
//        //            if (b.ExternalData is Projectile)
//        //                return true; //(((Laser)b.ExternalData).faction != self.faction);
//        //            else if (b.ExternalData is SecondaryWeapon)
//        //                return true; //(((Nuke)b.ExternalData).faction != self.faction);
//        //            else if (b.ExternalData is Ship)
//        //                return true; //(((Ship)b.ExternalData).faction != self.faction);
//        //            else if (b.ExternalData is Bonus)
//        //                return true; //(((Ship)b.ExternalData).faction != self.faction);
//        //            else if (b.ExternalData is Asteroid)
//        //                return true;
//        //            else return false;
//        //        };

//        //        var cs = this.geometry.CollisionSkin.Collisions;
//        //        if (cs.Count == 0)
//        //            return null;
//        //        return from c in cs
//        //               let collider = c.SkinInfo.Skin0.Owner == self.geometry ? c.SkinInfo.Skin1 : c.SkinInfo.Skin0
//        //               where is_enemy(collider.Owner)
//        //               select collider.Owner;
//        //    }
//        //}

//        public Res foldEnemies<Res>(Func<Body, Res, Res> fold, Res acc)
//        {
//            var cs = this.geometry.CollisionSkin.Collisions;
//            //for_each (var c in cs)
//            for (int i = 0; i < cs.Count; i++)
//            {
//                var c = cs[i];
//                var collider = c.SkinInfo.Skin0.Owner == this.geometry ? c.SkinInfo.Skin1.Owner : c.SkinInfo.Skin0.Owner;
//                if (collider.ExternalData is Projectile ||
//                    collider.ExternalData is SecondaryWeapon ||
//                    collider.ExternalData is Ship ||
//                    collider.ExternalData is Asteroid ||
//                    collider.ExternalData is Bonus)
//                    acc = fold(collider, acc);
//            }
//            return acc;
//        }

//    }

//    /// <summary>
//    /// Reference ad un ProjectileData
//    /// </summary>
//    public struct Projectile
//    {
//        public ProjectileData OwnValue { get { return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex]; } }

//        public Projectile(bool b)
//        {
//            self = StructAllocator<ProjectileData>.New();
//        }
//        public Reference self;

//        public Geometry geometry
//        {
//            get
//            {
//                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].geometry;
//            }
//            set
//            {
//                StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].geometry = value;
//            }
//        }


//        public float life
//        {
//            get
//            {
//                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].life;
//            }
//            set
//            {
//                StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].life = value;
//            }
//        }


//        public Faction faction
//        {
//            get
//            {
//                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].faction;
//            }
//            set
//            {
//                StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].faction = value;
//            }
//        }

//        public float age
//        {
//            get
//            {
//                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].age;
//            }
//            set
//            {
//                StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].age = value;
//            }
//        }

//        public float size
//        {
//            get
//            {
//                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].size;
//            }
//            set
//            {
//                StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].size = value;
//            }
//        }

//        //public IEnumerable<Body> DamagingColliders
//        //{
//        //    get
//        //    {
//        //        return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].DamagingColliders;
//        //    }
//        //}

//        public Res foldEnemies<Res>(Func<Body, Res, Res> fold, Res acc)
//        {
//            return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].foldEnemies(fold, acc);
//        }

//        public TargetType target_type
//        {
//            get
//            {
//                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].target_type;
//            }
//            set
//            {
//                StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].target_type = value;
//            }
//        }

//        public SecondaryWeapon target_nuke
//        {
//            get
//            {
//                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].target_nuke;
//            }
//            set
//            {
//                StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].target_nuke = value;
//            }
//        }

//        public Ship target_ship
//        {
//            get
//            {
//                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].target_ship;
//            }
//            set
//            {
//                StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].target_ship = value;
//            }
//        }

//        public Bonus target_bonus
//        {
//            get
//            {
//                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].target_bonus;
//            }
//            set
//            {
//                StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].target_bonus = value;
//            }
//        }

//        public WeaponConfig weapon_config
//        {
//            get
//            {
//                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].weapon_config;
//            }
//            set
//            {
//                StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].weapon_config = value;
//            }
//        }

//        public Ship shooter
//        {
//            get
//            {
//                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].shooter;
//            }
//            set
//            {
//                StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].shooter = value;
//            }
//        }

//        public Body shot_body
//        {
//            get
//            {
//                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].shooted_body;
//            }
//            set
//            {
//                StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].shooted_body = value;
//            }
//        }


//        public Geometry target_geometry
//        {
//            get
//            {
//                return StructAllocator<ProjectileData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].target_geometry;
//            }
//        }

//    }


//    /// <summary>
//    /// Una nave ha associata una vita residua.
//    /// </summary>
//    public struct Stats
//    {
//        public float MaxLife;
//        public float CurrentLife;
//    }


//    /// <summary>
//    /// Un motore ha una posizione relativa entro il modello della nave associata e
//    /// una potenza erogata corrente in percentuale.
//    /// </summary>
//    public struct EngineData : IActivable
//    {
//        public bool IsActive { get; set; }
//        public Vector3 Location;
//        public float Throttle;
//    }


//    /// <summary>
//    /// Reference ad un EngineData.
//    /// </summary>
//    public struct Engine
//    {
//        public Engine(bool b)
//        {
//            self = StructAllocator<EngineData>.New();
//        }
//        public Reference self;

//        public Vector3 Location
//        {
//            get
//            {
//                return StructAllocator<EngineData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].Location;
//            }
//            set
//            {
//                StructAllocator<EngineData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].Location = value;
//            }
//        }


//        public float Throttle
//        {
//            get
//            {
//                return StructAllocator<EngineData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].Throttle;
//            }
//            set
//            {
//                StructAllocator<EngineData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].Throttle = value;
//            }
//        }
//    }

//    /// <summary>
//    /// Una nave puó essere
//    /// * all'entrata del warp
//    /// * all'uscita del warp
//    /// * al di fuori del warp
//    /// </summary>
//    public enum WarpType
//    {
//        Entering,
//        Exiting,
//        None
//    }

//    /// <summary>
//    /// Definiamo una struttura per contenere un waypoint (o nulla se il
//    /// booleano é a false); performa meglio avere struct che classi, ma
//    /// se usiamo struct dobbiamo poter rappresentare un oggetto null
//    /// </summary>
//    public struct MaybeWaypoint
//    {
//        public Vector3 Position;
//        public bool HasValue;
//    }

//    /// <summary>
//    /// La nave del giocatore contiene:
//    /// * geometria
//    /// * vita corrente
//    /// * una lista di motori
//    /// * numero di vite residue
//    /// * informazioni sul warp
//    /// * prossimo waypoint
//    /// * timer per determinare se la nave puó sparare (per evitare che una nave spari troppo spesso)
//    /// * un numero di missili disponibili
//    /// </summary>
//    public struct PlayerShip
//    {
//        public static readonly float WARP_TRANSITION_TIME = 0.25f;

//        public int num_lives;
//        public float warp_state;
//        public float warping_in_timer;
//        public float warping_out_timer;
//        public WarpType warp_type;
//        public MaybeWaypoint waypoint;
//        public float shield;
//        public float age;
//        public float INVULNERABILITY_SPAWN_TIME;
//        public float[] shields_spawn_time;

//        public PlayerShip(bool b)
//        {
//            num_lives = 0;
//            warp_state = 1.0f;
//            warping_in_timer = 0.0f;
//            warping_out_timer = 0.0f;
//            warp_type = WarpType.None;
//            waypoint = new MaybeWaypoint();
//            self = StructAllocator<ShipData>.New();
//            shield = 0;
//            age = 0.0f;
//            INVULNERABILITY_SPAWN_TIME = 3.0f;
//            shields_spawn_time = new float[] { 0, 0, 0, 0 };
//        }
//        public Reference self;

//        public ShipData OwnValue { get { return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex]; } }

//        public int primary_active
//        {
//            get
//            {
//                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].primary_active;
//            }
//            set
//            {
//                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].primary_active = value;
//            }
//        }

//        public int secondary_active
//        {
//            get
//            {
//                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].secondary_active;
//            }
//            set
//            {
//                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].secondary_active = value;
//            }
//        }

//        public float energy
//        {
//            get
//            {
//                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].energy;
//            }
//            set
//            {
//                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].energy = value;
//            }
//        }

//        public float time_since_last_laser_shot
//        {
//            get
//            {
//                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].time_since_last_laser_shot;
//            }
//            set
//            {
//                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].time_since_last_laser_shot = value;
//            }
//        }

//        public float time_since_last_nuke_shot
//        {
//            get
//            {
//                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].time_since_last_nuke_shot;
//            }
//            set
//            {
//                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].time_since_last_nuke_shot = value;
//            }
//        }

//        public Geometry geometry
//        {
//            get
//            {
//                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].geometry;
//            }
//            set
//            {
//                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].geometry = value;
//            }
//        }


//        public Stats stats
//        {
//            get
//            {
//                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].stats;
//            }
//            set
//            {
//                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].stats = value;
//            }
//        }


//        public Engine[] engines
//        {
//            get
//            {
//                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].engines;
//            }
//            set
//            {
//                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].engines = value;
//            }
//        }

//        public Faction faction
//        {
//            get
//            {
//                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].faction;
//            }
//            set
//            {
//                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].faction = value;
//            }
//        }

//        //public IEnumerable<Body> DamagingColliders
//        //{
//        //    get
//        //    {
//        //        return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].DamagingColliders;
//        //    }
//        //}

//        public Res foldEnemies<Res>(Func<Body, Res, Res> fold, Res acc)
//        {
//            return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].foldEnemies(fold, acc);
//        }

//        public void Update(float dt, float max_speed)
//        {
//            geometry.Force = -geometry.Velocity * geometry.Mass * 2.0f;
//            geometry.Torque = Vector3.Transform(-geometry.AngularVelocity, geometry.BodyInertia) * 2.0f;
//            geometry.UpdateVelocity(dt);

//            var throttle = MathHelper.SmoothStep(0.0f, 1.0f, this.geometry.Velocity.Length() / max_speed);
//            for (int j = 0; j < this.engines.Length; j++)
//                this.engines[j].Throttle = throttle;
//        }

//        public Ship AsShip
//        {
//            get { return new Ship() { self = this.self }; }
//            set { self = value.self; }
//        }
//    }


//    public struct ShipDescription
//    {
//        public string ModelPath;
//        public float Speed;
//        public float TimeToWarp;
//        public float EnergyGeneratorLevel;
//        public float MaxShield;
//        public ArrayList<WeaponConfig> PrimaryWeapons;
//        public ArrayList<WeaponConfig> SecondaryWeapons;
//        //public int PrActiveWeapon;
//        //public int SeActiveWeapon;
//        public float LaserShotSpawnTime;
//        public float NukeShotSpawnTime;
//        public float Armor;
//        public bool ShockWaveOnExplode;
//        public ShockWaveData ShockWaveData;
//    }

//    /// <summary>
//    /// La nave contiene:
//    /// * geometria
//    /// * vita corrente
//    /// * una lista di motori
//    /// * una fazione
//    /// * timer per determinare se la nave puó sparare (per evitare che una nave spari troppo spesso)
//    /// * un numero di missili disponibili
//    /// </summary>
//    public struct ShipData : IActivable
//    {
//        public bool IsActive { get; set; }
//        public Geometry geometry;
//        public Stats stats;
//        public Engine[] engines;
//        public Faction faction;
//        public float time_since_last_laser_shot;
//        public float time_since_last_nuke_shot;
//        public float energy;
//        public int primary_active;
//        public int secondary_active;
//        public GarbageType ship_type;
//        public ShipDescription ship_description;


//        /// <summary>
//        /// Calcoliamo con DamagingColliders le entitá nemiche di questa che vi sono in collisione. Per
//        /// calcolarle andiamo a vedere tutte le geometrie in collisione, vediamo che entitá é associata
//        /// al tag (ExternalData) della geometria collidente e consultiamo il campo faction dell'entitá:
//        /// se la fazione del collisore é diversa dalla nostra, allora é un nemico con cui stiamo
//        /// collidendo.
//        /// </summary>
//        //public IEnumerable<Body> DamagingColliders
//        //{
//        //    get
//        //    {
//        //        var self = this;

//        //        Func<Body, bool> is_enemy = b =>
//        //        {
//        //            if (b.ExternalData is Projectile)
//        //                return true; //(((Laser)b.ExternalData).faction != self.faction);
//        //            else if (b.ExternalData is SecondaryWeapon)
//        //                return true; //(((Nuke)b.ExternalData).faction != self.faction);
//        //            else if (b.ExternalData is Ship)
//        //                return true; //(((Ship)b.ExternalData).faction != self.faction);
//        //            else if (b.ExternalData is Asteroid)
//        //                return true;
//        //            else return false;
//        //        };

//        //        var cs = this.geometry.CollisionSkin.Collisions;
//        //        if (cs.Count == 0)
//        //            return null;
//        //        return from c in cs
//        //               let collider = c.SkinInfo.Skin0.Owner == self.geometry ? c.SkinInfo.Skin1 : c.SkinInfo.Skin0
//        //               where is_enemy(collider.Owner)
//        //               select collider.Owner;
//        //    }
//        //}


//        public Res foldEnemies<Res>(Func<Body, Res, Res> fold, Res acc)
//        {
//            var cs = this.geometry.CollisionSkin.Collisions;
//            //for_each (var c in cs)
//            //{
//            for (int i = 0; i < cs.Count; i++)
//            {
//                var c = cs[i];
//                var collider = c.SkinInfo.Skin0.Owner == this.geometry ? c.SkinInfo.Skin1.Owner : c.SkinInfo.Skin0.Owner;
//                if (collider.ExternalData is Projectile ||
//                    collider.ExternalData is SecondaryWeapon ||
//                    collider.ExternalData is Ship ||
//                    collider.ExternalData is Asteroid)
//                    acc = fold(collider, acc);
//            }
//            return acc;
//        }
//    }

//    /// <summary>
//    /// Reference a ShipData.
//    /// </summary>
//    public struct Ship
//    {
//        public Ship(bool b)
//        {
//            self = StructAllocator<ShipData>.New();
//        }
//        public Reference self;

//        public ShipData OwnValue { get { return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex]; } }

//        public int primary_active
//        {
//            get
//            {
//                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].primary_active;
//            }
//            set
//            {
//                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].primary_active = value;
//            }
//        }

//        public int secondary_active
//        {
//            get
//            {
//                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].secondary_active;
//            }
//            set
//            {
//                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].secondary_active = value;
//            }
//        }

//        public float energy
//        {
//            get
//            {
//                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].energy;
//            }
//            set
//            {
//                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].energy = value;
//            }
//        }

//        public float time_since_last_laser_shot
//        {
//            get
//            {
//                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].time_since_last_laser_shot;
//            }
//            set
//            {
//                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].time_since_last_laser_shot = value;
//            }
//        }

//        public float time_since_last_nuke_shot
//        {
//            get
//            {
//                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].time_since_last_nuke_shot;
//            }
//            set
//            {
//                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].time_since_last_nuke_shot = value;
//            }
//        }

//        public Geometry geometry
//        {
//            get
//            {
//                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].geometry;
//            }
//            set
//            {
//                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].geometry = value;
//            }
//        }


//        public Stats stats
//        {
//            get
//            {
//                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].stats;
//            }
//            set
//            {
//                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].stats = value;
//            }
//        }


//        public Engine[] engines
//        {
//            get
//            {
//                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].engines;
//            }
//            set
//            {
//                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].engines = value;
//            }
//        }

//        public Faction faction
//        {
//            get
//            {
//                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].faction;
//            }
//            set
//            {
//                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].faction = value;
//            }
//        }

//        //public IEnumerable<Body> DamagingColliders
//        //{
//        //    get
//        //    {
//        //        return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].DamagingColliders;
//        //    }
//        //}

//        public Res foldEnemies<Res>(Func<Body, Res, Res> fold, Res acc)
//        {
//            return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].foldEnemies(fold, acc);
//        }

//        public GarbageType ship_type
//        {
//            get
//            {
//                return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].ship_type;
//            }

//            set
//            {
//                StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].ship_type = value;
//            }
//        }

//        public ShipDescription ship_description
//        {
//            get
//            { return StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].ship_description; }

//            set
//            { StructAllocator<ShipData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].ship_description = value; }
//        }



//        public void Update(float dt, float max_speed)
//        {
//            geometry.Force = -geometry.Velocity * geometry.Mass * 2.0f;
//            geometry.Torque = Vector3.Transform(-geometry.AngularVelocity, geometry.BodyInertia) * 2.0f;
//            geometry.UpdateVelocity(dt);

//            var throttle = MathHelper.SmoothStep(0.0f, 1.0f, this.geometry.Velocity.Length() / max_speed);
//            for (int j = 0; j < this.engines.Length; j++)
//                this.engines[j].Throttle = throttle;
//        }
//    }


//    /// <summary>
//    /// Una esplosione puó derivare da
//    /// * oggetti non specificati
//    /// * un missile
//    /// * una nave
//    /// * un proiettile
//    /// </summary>
//    public enum ExplosionType
//    {
//        None,
//        Nuke,
//        Ship,
//        Laser,
//        Asteroid
//    }

//    /// <summary>
//    /// Una esplosione ha un oggetto che le fa da origine (scelto in base alla 
//    /// flag explosion_type) e una posizione in cui va messa indipendentemente
//    /// dall'oggetto esploso.
//    /// </summary>
//    public struct ExplosionData : IActivable
//    {
//        public bool IsActive { get; set; }
//        public ExplosionType explosion_type;
//        public ProjectileData originating_laser;
//        public NukeData originating_nuke;
//        public ShipData originating_ship;
//        public AsteroidData originating_asteroid;
//        public Vector3 position;
//    }

//    /// <summary>
//    /// Reference a ExplosionData.
//    /// </summary>
//    public struct Explosion
//    {
//        public Explosion(bool b)
//        {
//            self = StructAllocator<ExplosionData>.New();
//        }
//        public Reference self;

//        public ExplosionType explosion_type
//        {
//            get
//            {
//                return StructAllocator<ExplosionData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].explosion_type;
//            }
//            set
//            {
//                StructAllocator<ExplosionData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].explosion_type = value;
//            }
//        }

//        public ShipData originating_ship
//        {
//            get
//            {
//                return StructAllocator<ExplosionData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].originating_ship;
//            }
//            set
//            {
//                StructAllocator<ExplosionData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].originating_ship = value;
//            }
//        }

//        public ProjectileData originating_laser
//        {
//            get
//            {
//                return StructAllocator<ExplosionData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].originating_laser;
//            }
//            set
//            {
//                StructAllocator<ExplosionData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].originating_laser = value;
//            }
//        }

//        public NukeData originating_nuke
//        {
//            get
//            {
//                return StructAllocator<ExplosionData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].originating_nuke;
//            }
//            set
//            {
//                StructAllocator<ExplosionData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].originating_nuke = value;
//            }
//        }


//        public AsteroidData originating_asteroid
//        {
//            get
//            {
//                return StructAllocator<ExplosionData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].originating_asteroid;
//            }
//            set
//            {
//                StructAllocator<ExplosionData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].originating_asteroid = value;
//            }
//        }

//        public Vector3 position
//        {
//            get
//            {
//                return StructAllocator<ExplosionData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].position;
//            }
//            set
//            {
//                StructAllocator<ExplosionData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].position = value;
//            }
//        }
//    }

//    public struct ShockWaveData : IActivable
//    {
//        public bool IsActive
//        {
//            get
//            {
//                return radius <= range && range != 0;
//            }
//            set
//            {
//            }
//        }
//        public Vector3 position;
//        public Color finalColor;
//        public Color initialColor;
//        public float speed;
//        public float range;
//        public Faction faction;
//        public float damage;
//        public float radius;
//    }

//    public struct ShockWave
//    {
//        public ShockWave(bool b)
//        {
//            self = StructAllocator<ShockWaveData>.New();
//        }
//        public Reference self;

//        public ShockWaveData OwnValue { get { return StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex]; } }

//        public Faction faction
//        {
//            get
//            {
//                return StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].faction;
//            }
//            set
//            {
//                StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].faction = value;
//            }
//        }
//        public Vector3 position
//        {
//            get
//            {
//                return StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].position;
//            }
//            set
//            {
//                StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].position = value;
//            }
//        }
//        public Color initialColor
//        {
//            get
//            {
//                return StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].initialColor;
//            }
//            set
//            {
//                StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].initialColor = value;
//            }
//        }
//        public Color finalColor
//        {
//            get
//            {
//                return StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].finalColor;
//            }
//            set
//            {
//                StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].finalColor = value;
//            }
//        }
//        public float speed
//        {
//            get
//            {
//                return StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].speed;
//            }
//            set
//            {
//                StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].speed = value;
//            }
//        }
//        public float damage
//        {
//            get
//            {
//                return StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].damage;
//            }
//            set
//            {
//                StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].damage = value;
//            }
//        }
//        public float radius
//        {
//            get
//            {
//                return StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].radius;
//            }
//            set
//            {
//                StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].radius = value;
//            }
//        }
//        public float range
//        {
//            get
//            {
//                return StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].range;
//            }
//            set
//            {
//                StructAllocator<ShockWaveData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].range = value;
//            }
//        }
//    }

//    /// <summary>
//    /// Un missile nucleare contiene una geometria, una fazione, un timer (per eliminare i vecchi missili che
//    /// non hanno raggiunto l'obiettivo) e una dimensione.
//    /// </summary>
//    public struct AsteroidData : IActivable
//    {
//        public bool IsActive { get; set; }

//        public Geometry geometry;
//        public float size;
//        public Stats stat;

//        /////// <summary>
//        /////// Calcoliamo con DamagingColliders le entitá che vi sono in collisione. Per
//        /////// calcolarle andiamo a vedere tutte le geometrie in collisione, vediamo che entitá é associata
//        /////// al tag (ExternalData) della geometria collidente.
//        /////// </summary>
//        //public IEnumerable<Body> DamagingColliders
//        //{
//        //    get
//        //    {
//        //        var self = this;

//        //        Func<Body, bool> is_enemy = b =>
//        //        {
//        //            if (b.ExternalData is Projectile)
//        //                return true;
//        //            else if (b.ExternalData is SecondaryWeapon)
//        //                return true;
//        //            else if (b.ExternalData is Ship)
//        //                return true;
//        //            else return false;
//        //        };

//        //        if (this.geometry != null)
//        //        {
//        //            var cs = this.geometry.CollisionSkin.Collisions;
//        //            if (cs.Count == 0)
//        //                return null;
//        //            return from c in cs
//        //                   let collider = c.SkinInfo.Skin0.Owner == self.geometry ? c.SkinInfo.Skin1 : c.SkinInfo.Skin0
//        //                   where is_enemy(collider.Owner)
//        //                   select collider.Owner;
//        //        }
//        //        return null;
//        //    }
//        //}

//        //public void Damaging_Colliders(List<Body> acc)
//        //{
//        //    var self = this;

//        //    var cs = this.geometry.CollisionSkin.Collisions;
//        //    for_each (var c in cs)
//        //    {
//        //        var collider = c.SkinInfo.Skin0.Owner == self.geometry ? c.SkinInfo.Skin1 : c.SkinInfo.Skin0;
//        //        if (collider.Owner.ExternalData is Projectile) 
//        //            acc.Add(collider.Owner);

//        //    }
//        //}

//        public Res foldEnemies<Res>(Func<Body, Res, Res> fold, Res acc)
//        {
//            var cs = this.geometry.CollisionSkin.Collisions;
//            //for_each (var c in cs)
//            //{
//            for (int i = 0; i < cs.Count; i++)
//            {
//                var c = cs[i];
//                var collider = c.SkinInfo.Skin0.Owner == this.geometry ? c.SkinInfo.Skin1.Owner : c.SkinInfo.Skin0.Owner;
//                if (collider.ExternalData is Projectile ||
//                    collider.ExternalData is SecondaryWeapon ||
//                    collider.ExternalData is Ship)
//                    acc = fold(collider, acc);
//            }
//            return acc;
//        }
//    }


//    /// <summary>
//    /// Asteroid é il tipo di una reference (che fa anche da proxy) ad un AsteroidData
//    /// </summary>
//    public struct Asteroid
//    {
//        public AsteroidData OwnValue { get { return StructAllocator<AsteroidData>.Chunks[self.ChunkIndex].Items[self.ItemIndex]; } }

//        public Asteroid(bool b)
//        {
//            self = StructAllocator<AsteroidData>.New();
//        }

//        public Reference self;

//        public Geometry geometry
//        {
//            get
//            {
//                return StructAllocator<AsteroidData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].geometry;
//            }
//            set
//            {
//                StructAllocator<AsteroidData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].geometry = value;
//            }
//        }

//        public float size
//        {
//            get
//            {
//                return StructAllocator<AsteroidData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].size;
//            }
//            set
//            {
//                StructAllocator<AsteroidData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].size = value;
//            }
//        }

//        public Stats stat
//        {
//            get
//            {
//                return StructAllocator<AsteroidData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].stat;
//            }
//            set
//            {
//                StructAllocator<AsteroidData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].stat = value;
//            }
//        }

//        //public IEnumerable<Body> DamagingColliders
//        //{
//        //    get
//        //    {
//        //        return StructAllocator<AsteroidData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].DamagingColliders;
//        //    }
//        //}


//        //public void Damaging_Colliders(List<Body> acc)
//        //{
//        //        StructAllocator<AsteroidData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].Damaging_Colliders(acc);
//        //}

//        public Res foldEnemies<Res>(Func<Body, Res, Res> fold, Res acc)
//        {
//                return StructAllocator<AsteroidData>.Chunks[self.ChunkIndex].Items[self.ItemIndex].foldEnemies(fold, acc);
//        }
//    }



//}
